1 Functions

2 Data

# read processed data:
SCC1_cancer  = readRDS(file = "./Data/cervical_cancer_data/Qiu et al/SCC1/SCC1_cancer.RDS")
SCC2_cancer  = readRDS(file = "./Data/cervical_cancer_data/Qiu et al/SCC2/SCC2_cancer_processed.RDS")
SCC3_cancer = readRDS(file = "./Data/cervical_cancer_data/Qiu et al/SCC3/SCC3_cancer_processed.RDS")
SCC4_cancer = readRDS(file = "./Data/cervical_cancer_data/Qiu et al/SCC4/SCC4_cancer_processed.RDS")
SCC5_cancer  = readRDS(file = "./Data/cervical_cancer_data/Qiu et al/SCC5/SCC5_cancer_processed.RDS")

scc.big <- merge(SCC1_cancer, y = c(SCC2_cancer,SCC3_cancer, SCC4_cancer,SCC5_cancer), add.cell.ids = c("SCC1","SCC2", "SCC3", "SCC4","SCC5"), project = "SCC")
scc.big$orig.ident =  sapply(X = strsplit(colnames(scc.big), split = "_"), FUN = "[", 1)


VlnPlot(object = scc.big,features = "MYB",group.by = "orig.ident",slot = "data", assay = "RNA")

NA
NA
b = FetchData(object = scc.big,vars = c("MYB","orig.ident"),slot = "data", assay = "RNA")
b %>%   group_by(orig.ident) %>% 
  summarise(counts = sum(MYB > 0, na.rm = TRUE))

3 Violin plot all patients without scc2

scc_myb_patients<- subset(scc.big, subset = orig.ident %in% c("SCC3","SCC4","SCC5"))
library(rstatix)
myb_vs_hpv = FetchData(object = scc_myb_patients, vars = c("hpv_positive", "MYB"))
df = reshape2::melt(myb_vs_hpv,value.name = "logTPM") %>% dplyr::rename(gene = variable)
Using hpv_positive as id variables
stat.test <- df %>%
  wilcox_test(logTPM ~ hpv_positive)

stat.test



p = ggplot(myb_vs_hpv,aes( x = hpv_positive, y = MYB))+ 
    geom_violin(trim=FALSE,aes(fill = hpv_positive)) +
  theme_minimal()+
  stat_summary(fun.data = function(x) data.frame(y=max(x)*1.15, label = paste("Mean=",round(mean(x),digits = 2))), geom="text") +ylab("average MYB")+ggtitle("all patients") +
  stat_pvalue_manual(stat.test,y.position = 3, label = "Wilcox, p = {p}",remove.bracket = F)+
  geom_boxplot(width=.1, outlier.shape=NA) 


p

pdf(file = "./Figures/SCC_myb_hpv_violin_all_patients.pdf")
p
dev.off()
null device 
          1 

4 Violin plot all patients with scc2

scc_myb_patients<- subset(scc.big, subset = orig.ident %in% c("SCC2","SCC3","SCC4","SCC5"))
library(rstatix)
myb_vs_hpv = FetchData(object = scc_myb_patients, vars = c("hpv_positive", "MYB"))
df = reshape2::melt(myb_vs_hpv,value.name = "logTPM") %>% dplyr::rename(gene = variable)
Using hpv_positive as id variables
stat.test <- df %>%
  wilcox_test(logTPM ~ hpv_positive)

stat.test



p = ggplot(myb_vs_hpv,aes( x = hpv_positive, y = MYB))+ 
    geom_violin(trim=FALSE,aes(fill = hpv_positive)) +
  theme_minimal()+
  stat_summary(fun.data = function(x) data.frame(y=max(x)*1.15, label = paste("Mean=",round(mean(x),digits = 2))), geom="text") +ylab("average MYB")+ggtitle("all patients") +
  stat_pvalue_manual(stat.test,y.position = 3, label = "Wilcox, p = {p}",remove.bracket = F)+
  geom_boxplot(width=.1, outlier.shape=NA) 


p

5 Boxplot by patient

pdf(file = "./Figures/SCC_HPV_MYB_boxplot_bySample.pdf",width = 8)
p
dev.off()
null device 
          1 

6 All genes boxplots

genes = c("ANLN", "TUBB6", "AXL", "IFT122", "GFM1", "MYB", "JAG1")
myb_vs_hpv = FetchData(object = scc_myb_patients,vars = c("hpv_positive",genes))
df = reshape2::melt(myb_vs_hpv,value.name = "logTPM") %>% dplyr::rename(gene = variable)
Using hpv_positive as id variables
stat.test <- df %>%
    group_by(gene) %>%
  wilcox_test(logTPM ~ hpv_positive) %>%
  mutate(y.position = 5)

stat.test

stat.test <- stat.test %>% 
  add_xy_position(x = "gene", dodge = 0.8)

p = ggboxplot(
  df,
  x = "gene",
  y = "logTPM",
  color = "hpv_positive",
  palette = "jco",
  add = "jitter"
)+ stat_pvalue_manual(stat.test,y.position = 4, label = "p = {p}",remove.bracket = T)

p

pdf(file = "./Figures/SCC_HPV_genes_all_patients.pdf",width = 8)
p
dev.off()
metagenes_violin_compare.2 = function(dataset,prefix = "",pre_on = c("OSI","NT"),axis.text.x = 11,test = "t.test", programs = c("Hypoxia","TNFa","Cell_cycle"),return_list = F,combine_patients = F){
  require(facefuns)
  plt.lst = list()
  if(combine_patients){
    genes_by_tp = FetchData(object = dataset,vars =  c("treatment",programs)) %>% filter(treatment %in% pre_on)  %>% as.data.frame() #mean expression
    formula <- as.formula( paste("c(", paste(programs, collapse = ","), ")~ treatment ") )
    
    #plot and split by patient:   
    stat.test = compare_means(formula = formula ,data = genes_by_tp,method = test,p.adjust.method = "fdr")%>% # Add pairwise comparisons p-value
      dplyr::filter(group1 == pre_on[1] & group2 == pre_on[2])  #filter for pre vs on treatment only
    
    stat.test$p.format =stat.test$p.adj #modift 0 pvalue to be lowest possible float
    stat.test$p.format[!stat.test$p.format == 0 ] <- paste("=",stat.test$p.format[!stat.test$p.format == 0 ])
    stat.test$p.format[stat.test$p.format == 0 ] <- paste("<",.Machine$double.xmin %>% signif(digits = 3))
    
    
    genes_by_tp = reshape2::melt(genes_by_tp, id.vars = c("treatment"),value.name = "score")
    plt = ggplot(genes_by_tp, aes(x = variable, y = score,fill = treatment)) + geom_split_violin(scale = 'width')+ 
      geom_boxplot(width = 0.25, notch = FALSE, notchwidth = .4, outlier.shape = NA, coef=0)+
      ylim(min(genes_by_tp$score),max(genes_by_tp$score)*1.25)
    plt = plt +stat_pvalue_manual(stat.test, label = "{p.signif}", label.size = 7,  #add p value
                                  y.position = 1.5,inherit.aes = F,size = 3.3,x = ".y.") # set position at the top value
    return(plt)
  }
  
  
  
  
  
  if (return_list) {
    return(plt.lst)
  }
}
scc_myb_patients$treatment = scc_myb_patients$hpv_positive %>% gsub(pattern = "negative",replacement = "HPV-negative")%>% gsub(pattern = "positive",replacement = "HPV-positive")
Error in h(simpleError(msg, call)) : 
  error in evaluating the argument 'x' in selecting a method for function 'gsub': error in evaluating the argument 'x' in selecting a method for function 'gsub': object 'scc_myb_patients' not found
pdf(file = "./Figures/SCC_HPV_Top_violin.pdf",width = 10,height = 5)
p
Warning: Removed 392 rows containing non-finite values (stat_ydensity).
Warning: Removed 392 rows containing non-finite values (stat_boxplot).
dev.off()
null device 
          1 
myplots <- list()  # new empty list

for (patient_name in c("SCC2", "SCC3", "SCC4", "SCC5")) {
  patient_data = subset(x = scc_myb_patients, subset = orig.ident == patient_name)
  df  = FetchData(object = patient_data,
                  vars = c("hpv_positive", "MYB_positive")) %>% droplevels()
  test = fisher_test(table(df))
  p = ggbarstats(
    df,
    MYB_positive,
    hpv_positive,
    results.subtitle = FALSE,
    subtitle = paste0("Fisher's exact test", ", p-value = ",
                      test$p)
  ,title = patient_name)
  myplots[[patient_name]] <- p  # add each plot into plot list

}
ggarrange(plotlist = myplots,ncol = 4,nrow = 1)

  fisher.test(table(df))

    Fisher's Exact Test for Count Data

data:  table(df)
p-value < 2.2e-16
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
 2.236243 3.479375
sample estimates:
odds ratio 
  2.786281 
  fisher_test(table(df))
NA
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMQotLS0KCgoKIyBGdW5jdGlvbnMKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmBgYAoKYGBge3J9CmBgYAoKIyBEYXRhCgoKYGBge3J9CiMgcmVhZCBwcm9jZXNzZWQgZGF0YToKU0NDMV9jYW5jZXIgID0gcmVhZFJEUyhmaWxlID0gIi4vRGF0YS9jZXJ2aWNhbF9jYW5jZXJfZGF0YS9RaXUgZXQgYWwvU0NDMS9TQ0MxX2NhbmNlci5SRFMiKQpTQ0MyX2NhbmNlciAgPSByZWFkUkRTKGZpbGUgPSAiLi9EYXRhL2NlcnZpY2FsX2NhbmNlcl9kYXRhL1FpdSBldCBhbC9TQ0MyL1NDQzJfY2FuY2VyX3Byb2Nlc3NlZC5SRFMiKQpTQ0MzX2NhbmNlciA9IHJlYWRSRFMoZmlsZSA9ICIuL0RhdGEvY2VydmljYWxfY2FuY2VyX2RhdGEvUWl1IGV0IGFsL1NDQzMvU0NDM19jYW5jZXJfcHJvY2Vzc2VkLlJEUyIpClNDQzRfY2FuY2VyID0gcmVhZFJEUyhmaWxlID0gIi4vRGF0YS9jZXJ2aWNhbF9jYW5jZXJfZGF0YS9RaXUgZXQgYWwvU0NDNC9TQ0M0X2NhbmNlcl9wcm9jZXNzZWQuUkRTIikKU0NDNV9jYW5jZXIgID0gcmVhZFJEUyhmaWxlID0gIi4vRGF0YS9jZXJ2aWNhbF9jYW5jZXJfZGF0YS9RaXUgZXQgYWwvU0NDNS9TQ0M1X2NhbmNlcl9wcm9jZXNzZWQuUkRTIikKCnNjYy5iaWcgPC0gbWVyZ2UoU0NDMV9jYW5jZXIsIHkgPSBjKFNDQzJfY2FuY2VyLFNDQzNfY2FuY2VyLCBTQ0M0X2NhbmNlcixTQ0M1X2NhbmNlciksIGFkZC5jZWxsLmlkcyA9IGMoIlNDQzEiLCJTQ0MyIiwgIlNDQzMiLCAiU0NDNCIsIlNDQzUiKSwgcHJvamVjdCA9ICJTQ0MiKQpzY2MuYmlnJG9yaWcuaWRlbnQgPSAgc2FwcGx5KFggPSBzdHJzcGxpdChjb2xuYW1lcyhzY2MuYmlnKSwgc3BsaXQgPSAiXyIpLCBGVU4gPSAiWyIsIDEpCgoKVmxuUGxvdChvYmplY3QgPSBzY2MuYmlnLGZlYXR1cmVzID0gIk1ZQiIsZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIsc2xvdCA9ICJkYXRhIiwgYXNzYXkgPSAiUk5BIikKCgpgYGAKCgpgYGB7cn0KbXliX2RhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gc2NjLmJpZyx2YXJzID0gYygiTVlCIiwib3JpZy5pZGVudCIpLHNsb3QgPSAiZGF0YSIsIGFzc2F5ID0gIlJOQSIpCm15Yl9kYXRhICU+JSAgIGdyb3VwX2J5KG9yaWcuaWRlbnQpICU+JSAKICBzdW1tYXJpc2UoY291bnRzID0gc3VtKE1ZQiA+IDAsIG5hLnJtID0gVFJVRSkpCmBgYAoKCiMgVmlvbGluIHBsb3QgYWxsIHBhdGllbnRzIHdpdGhvdXQgc2NjMgpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMn0Kc2NjX215Yl9wYXRpZW50czwtIHN1YnNldChzY2MuYmlnLCBzdWJzZXQgPSBvcmlnLmlkZW50ICVpbiUgYygiU0NDMyIsIlNDQzQiLCJTQ0M1IikpCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KHJzdGF0aXgpCm15Yl92c19ocHYgPSBGZXRjaERhdGEob2JqZWN0ID0gc2NjX215Yl9wYXRpZW50cywgdmFycyA9IGMoImhwdl9wb3NpdGl2ZSIsICJNWUIiKSkKZGYgPSByZXNoYXBlMjo6bWVsdChteWJfdnNfaHB2LHZhbHVlLm5hbWUgPSAibG9nVFBNIikgJT4lIGRwbHlyOjpyZW5hbWUoZ2VuZSA9IHZhcmlhYmxlKQoKc3RhdC50ZXN0IDwtIGRmICU+JQogIHdpbGNveF90ZXN0KGxvZ1RQTSB+IGhwdl9wb3NpdGl2ZSkKCnN0YXQudGVzdAoKCgpwID0gZ2dwbG90KG15Yl92c19ocHYsYWVzKCB4ID0gaHB2X3Bvc2l0aXZlLCB5ID0gTVlCKSkrIAogICAgZ2VvbV92aW9saW4odHJpbT1GQUxTRSxhZXMoZmlsbCA9IGhwdl9wb3NpdGl2ZSkpICsKICB0aGVtZV9taW5pbWFsKCkrCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gZnVuY3Rpb24oeCkgZGF0YS5mcmFtZSh5PW1heCh4KSoxLjE1LCBsYWJlbCA9IHBhc3RlKCJNZWFuPSIscm91bmQobWVhbih4KSxkaWdpdHMgPSAyKSkpLCBnZW9tPSJ0ZXh0IikgK3lsYWIoImF2ZXJhZ2UgTVlCIikrZ2d0aXRsZSgiYWxsIHBhdGllbnRzIikgKwogIHN0YXRfcHZhbHVlX21hbnVhbChzdGF0LnRlc3QseS5wb3NpdGlvbiA9IDMsIGxhYmVsID0gIldpbGNveCwgcCA9IHtwfSIscmVtb3ZlLmJyYWNrZXQgPSBGKSsKICBnZW9tX2JveHBsb3Qod2lkdGg9LjEsIG91dGxpZXIuc2hhcGU9TkEpIAoKCnAKYGBgCmBgYHtyfQpwZGYoZmlsZSA9ICIuL0ZpZ3VyZXMvU0NDX215Yl9ocHZfdmlvbGluX2FsbF9wYXRpZW50cy5wZGYiKQpwCmRldi5vZmYoKQpgYGAKIyBWaW9saW4gcGxvdCBhbGwgcGF0aWVudHMgd2l0aCBzY2MyCgpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMn0Kc2NjX215Yl9wYXRpZW50czwtIHN1YnNldChzY2MuYmlnLCBzdWJzZXQgPSBvcmlnLmlkZW50ICVpbiUgYygiU0NDMiIsIlNDQzMiLCJTQ0M0IiwiU0NDNSIpKQpgYGAKCgpgYGB7cn0KbGlicmFyeShyc3RhdGl4KQpteWJfdnNfaHB2ID0gRmV0Y2hEYXRhKG9iamVjdCA9IHNjY19teWJfcGF0aWVudHMsIHZhcnMgPSBjKCJocHZfcG9zaXRpdmUiLCAiTVlCIikpCmRmID0gcmVzaGFwZTI6Om1lbHQobXliX3ZzX2hwdix2YWx1ZS5uYW1lID0gImxvZ1RQTSIpICU+JSBkcGx5cjo6cmVuYW1lKGdlbmUgPSB2YXJpYWJsZSkKCnN0YXQudGVzdCA8LSBkZiAlPiUKICB3aWxjb3hfdGVzdChsb2dUUE0gfiBocHZfcG9zaXRpdmUpCgpzdGF0LnRlc3QKCgoKcCA9IGdncGxvdChteWJfdnNfaHB2LGFlcyggeCA9IGhwdl9wb3NpdGl2ZSwgeSA9IE1ZQikpKyAKICAgIGdlb21fdmlvbGluKHRyaW09RkFMU0UsYWVzKGZpbGwgPSBocHZfcG9zaXRpdmUpKSArCiAgdGhlbWVfbWluaW1hbCgpKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IGZ1bmN0aW9uKHgpIGRhdGEuZnJhbWUoeT1tYXgoeCkqMS4xNSwgbGFiZWwgPSBwYXN0ZSgiTWVhbj0iLHJvdW5kKG1lYW4oeCksZGlnaXRzID0gMikpKSwgZ2VvbT0idGV4dCIpICt5bGFiKCJhdmVyYWdlIE1ZQiIpK2dndGl0bGUoImFsbCBwYXRpZW50cyIpICsKICBzdGF0X3B2YWx1ZV9tYW51YWwoc3RhdC50ZXN0LHkucG9zaXRpb24gPSAzLCBsYWJlbCA9ICJXaWxjb3gsIHAgPSB7cH0iLHJlbW92ZS5icmFja2V0ID0gRikrCiAgZ2VvbV9ib3hwbG90KHdpZHRoPS4xLCBvdXRsaWVyLnNoYXBlPU5BKSAKCgpwCmBgYAoKCiMgQm94cGxvdCBieSBwYXRpZW50CmBgYHtyfQpzY2NfbXliX3BhdGllbnRzPC0gc3Vic2V0KHNjYy5iaWcsIHN1YnNldCA9IG9yaWcuaWRlbnQgJWluJSBjKCJTQ0MyIiwiU0NDMyIsIlNDQzQiLCJTQ0M1IikpCgpkZiA9IEZldGNoRGF0YShvYmplY3QgPSBzY2NfbXliX3BhdGllbnRzLHZhcnMgPSBjKCJvcmlnLmlkZW50IiwiTVlCIiwiaHB2X3Bvc2l0aXZlIikpICU+JSBncm91cF9ieShvcmlnLmlkZW50LGhwdl9wb3NpdGl2ZSkgJT4lIHN1bW1hcmlzZSgKICBteWIgPSBtZWFuKE1ZQiksLmdyb3VwcyA9ICJkcm9wX2xhc3QiKQpzdGF0LnRlc3QgPC0gZGYgJT4lIGdyb3VwX2J5KCJocHZfcG9zaXRpdmUiKSAlPiUgCiAgd2lsY294X3Rlc3QobXliIH4gaHB2X3Bvc2l0aXZlKQoKCmRmID0gcmVzaGFwZTI6OmRjYXN0KGRmLCBvcmlnLmlkZW50IH4gaHB2X3Bvc2l0aXZlKQoKCnAgPSBnZ3BhaXJlZChkZiwgY29uZDEgID0gInBvc2l0aXZlIixjb25kMiAgID0gIm5lZ2F0aXZlIixwYWxldHRlID0gImpjbyIsCiAgICAgICAgICAgIGFkZCA9ICJqaXR0ZXIiLCBsaW5lLmNvbG9yID0gImdyYXkiLCBsaW5lLnNpemUgPSAwLjQsaWQgPSAib3JpZy5pZGVudCIsIGZpbGwgPSAiY29uZGl0aW9uIikgKyB0aGVtZV9taW5pbWFsKCkrCiAgIyBzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gIndpbGNveC50ZXN0Iixjb21wYXJpc29ucyA9IGxpc3QoYygicG9zaXRpdmUiLCJuZWdhdGl2ZSIpKSxwYWlyZWQgPSBGKSsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBmdW5jdGlvbih4KSBkYXRhLmZyYW1lKHk9bWF4KHgpKjEuMiwgbGFiZWwgPSBwYXN0ZSgiTWVhbj0iLHJvdW5kKG1lYW4oeCksZGlnaXRzID0gMikpKSwgZ2VvbT0idGV4dCIpK3lsYWIoIk1ZQiIpKyBzdGF0X3B2YWx1ZV9tYW51YWwoc3RhdC50ZXN0LHkucG9zaXRpb24gPSAwLjIsIGxhYmVsID0gIldpbGNveCwgcCA9IHtwfSIscmVtb3ZlLmJyYWNrZXQgPSBGKQpwCmBgYApgYGB7cn0KcGRmKGZpbGUgPSAiLi9GaWd1cmVzL1NDQ19IUFZfTVlCX2JveHBsb3RfYnlTYW1wbGUucGRmIix3aWR0aCA9IDgpCnAKZGV2Lm9mZigpCmBgYAojIEFsbCBnZW5lcyBib3hwbG90cwoKYGBge3IgZmlnLndpZHRoPTh9CmdlbmVzID0gYygiQU5MTiIsICJUVUJCNiIsICJBWEwiLCAiSUZUMTIyIiwgIkdGTTEiLCAiTVlCIiwgIkpBRzEiKQpteWJfdnNfaHB2ID0gRmV0Y2hEYXRhKG9iamVjdCA9IHNjY19teWJfcGF0aWVudHMsdmFycyA9IGMoImhwdl9wb3NpdGl2ZSIsZ2VuZXMpKQpkZiA9IHJlc2hhcGUyOjptZWx0KG15Yl92c19ocHYsdmFsdWUubmFtZSA9ICJsb2dUUE0iKSAlPiUgZHBseXI6OnJlbmFtZShnZW5lID0gdmFyaWFibGUpCgoKc3RhdC50ZXN0IDwtIGRmICU+JQogICAgZ3JvdXBfYnkoZ2VuZSkgJT4lCiAgd2lsY294X3Rlc3QobG9nVFBNIH4gaHB2X3Bvc2l0aXZlKSAlPiUKICBtdXRhdGUoeS5wb3NpdGlvbiA9IDUpCgpzdGF0LnRlc3QKCnN0YXQudGVzdCA8LSBzdGF0LnRlc3QgJT4lIAogIGFkZF94eV9wb3NpdGlvbih4ID0gImdlbmUiLCBkb2RnZSA9IDAuOCkKCnAgPSBnZ2JveHBsb3QoCiAgZGYsCiAgeCA9ICJnZW5lIiwKICB5ID0gImxvZ1RQTSIsCiAgY29sb3IgPSAiaHB2X3Bvc2l0aXZlIiwKICBwYWxldHRlID0gImpjbyIsCiAgYWRkID0gImppdHRlciIKKSsgc3RhdF9wdmFsdWVfbWFudWFsKHN0YXQudGVzdCx5LnBvc2l0aW9uID0gNCwgbGFiZWwgPSAicCA9IHtwfSIscmVtb3ZlLmJyYWNrZXQgPSBUKQoKcApgYGAKYGBge3J9CnBkZihmaWxlID0gIi4vRmlndXJlcy9TQ0NfSFBWX2dlbmVzX2FsbF9wYXRpZW50cy5wZGYiLHdpZHRoID0gOCkKcApkZXYub2ZmKCkKYGBgCgpgYGB7cn0KbWV0YWdlbmVzX3Zpb2xpbl9jb21wYXJlLjIgPSBmdW5jdGlvbihkYXRhc2V0LHByZWZpeCA9ICIiLHByZV9vbiA9IGMoIk9TSSIsIk5UIiksYXhpcy50ZXh0LnggPSAxMSx0ZXN0ID0gInQudGVzdCIsIHByb2dyYW1zID0gYygiSHlwb3hpYSIsIlRORmEiLCJDZWxsX2N5Y2xlIikscmV0dXJuX2xpc3QgPSBGLGNvbWJpbmVfcGF0aWVudHMgPSBGKXsKICByZXF1aXJlKGZhY2VmdW5zKQogIHBsdC5sc3QgPSBsaXN0KCkKICBpZihjb21iaW5lX3BhdGllbnRzKXsKICAgIGdlbmVzX2J5X3RwID0gRmV0Y2hEYXRhKG9iamVjdCA9IGRhdGFzZXQsdmFycyA9ICBjKCJ0cmVhdG1lbnQiLHByb2dyYW1zKSkgJT4lIGZpbHRlcih0cmVhdG1lbnQgJWluJSBwcmVfb24pICAlPiUgYXMuZGF0YS5mcmFtZSgpICNtZWFuIGV4cHJlc3Npb24KICAgIGZvcm11bGEgPC0gYXMuZm9ybXVsYSggcGFzdGUoImMoIiwgcGFzdGUocHJvZ3JhbXMsIGNvbGxhcHNlID0gIiwiKSwgIil+IHRyZWF0bWVudCAiKSApCiAgICAKICAgICNwbG90IGFuZCBzcGxpdCBieSBwYXRpZW50OiAgIAogICAgc3RhdC50ZXN0ID0gY29tcGFyZV9tZWFucyhmb3JtdWxhID0gZm9ybXVsYSAsZGF0YSA9IGdlbmVzX2J5X3RwLG1ldGhvZCA9IHRlc3QscC5hZGp1c3QubWV0aG9kID0gImZkciIpJT4lICMgQWRkIHBhaXJ3aXNlIGNvbXBhcmlzb25zIHAtdmFsdWUKICAgICAgZHBseXI6OmZpbHRlcihncm91cDEgPT0gcHJlX29uWzFdICYgZ3JvdXAyID09IHByZV9vblsyXSkgICNmaWx0ZXIgZm9yIHByZSB2cyBvbiB0cmVhdG1lbnQgb25seQogICAgCiAgICBzdGF0LnRlc3QkcC5mb3JtYXQgPXN0YXQudGVzdCRwLmFkaiAjbW9kaWZ0IDAgcHZhbHVlIHRvIGJlIGxvd2VzdCBwb3NzaWJsZSBmbG9hdAogICAgc3RhdC50ZXN0JHAuZm9ybWF0WyFzdGF0LnRlc3QkcC5mb3JtYXQgPT0gMCBdIDwtIHBhc3RlKCI9IixzdGF0LnRlc3QkcC5mb3JtYXRbIXN0YXQudGVzdCRwLmZvcm1hdCA9PSAwIF0pCiAgICBzdGF0LnRlc3QkcC5mb3JtYXRbc3RhdC50ZXN0JHAuZm9ybWF0ID09IDAgXSA8LSBwYXN0ZSgiPCIsLk1hY2hpbmUkZG91YmxlLnhtaW4gJT4lIHNpZ25pZihkaWdpdHMgPSAzKSkKICAgIAogICAgCiAgICBnZW5lc19ieV90cCA9IHJlc2hhcGUyOjptZWx0KGdlbmVzX2J5X3RwLCBpZC52YXJzID0gYygidHJlYXRtZW50IiksdmFsdWUubmFtZSA9ICJzY29yZSIpCiAgICBwbHQgPSBnZ3Bsb3QoZ2VuZXNfYnlfdHAsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBzY29yZSxmaWxsID0gdHJlYXRtZW50KSkgKyBnZW9tX3NwbGl0X3Zpb2xpbihzY2FsZSA9ICd3aWR0aCcpKyAKICAgICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4yNSwgbm90Y2ggPSBGQUxTRSwgbm90Y2h3aWR0aCA9IC40LCBvdXRsaWVyLnNoYXBlID0gTkEsIGNvZWY9MCkrCiAgICAgIHlsaW0obWluKGdlbmVzX2J5X3RwJHNjb3JlKSxtYXgoZ2VuZXNfYnlfdHAkc2NvcmUpKjEuMjUpCiAgICBwbHQgPSBwbHQgK3N0YXRfcHZhbHVlX21hbnVhbChzdGF0LnRlc3QsIGxhYmVsID0gIntwLnNpZ25pZn0iLCBsYWJlbC5zaXplID0gNywgICNhZGQgcCB2YWx1ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeS5wb3NpdGlvbiA9IDEuNSxpbmhlcml0LmFlcyA9IEYsc2l6ZSA9IDMuMyx4ID0gIi55LiIpICMgc2V0IHBvc2l0aW9uIGF0IHRoZSB0b3AgdmFsdWUKICAgIHJldHVybihwbHQpCiAgfQogIAogIAogIAogIAogIAogIGlmIChyZXR1cm5fbGlzdCkgewogICAgcmV0dXJuKHBsdC5sc3QpCiAgfQp9CmBgYAoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CnNjY19teWJfcGF0aWVudHMkdHJlYXRtZW50ID0gc2NjX215Yl9wYXRpZW50cyRocHZfcG9zaXRpdmUgJT4lIGdzdWIocGF0dGVybiA9ICJuZWdhdGl2ZSIscmVwbGFjZW1lbnQgPSAiSFBWLW5lZ2F0aXZlIiklPiUgZ3N1YihwYXR0ZXJuID0gInBvc2l0aXZlIixyZXBsYWNlbWVudCA9ICJIUFYtcG9zaXRpdmUiKQpzY2NfbXliX3BhdGllbnRzQG1ldGEuZGF0YVtbInRyZWF0bWVudCJdXSA9IGZhY3RvcihzY2NfbXliX3BhdGllbnRzJHRyZWF0bWVudCwgbGV2ZWxzID0gYygiSFBWLXBvc2l0aXZlIiwgIkhQVi1uZWdhdGl2ZSIpKQoKcCA9IG1ldGFnZW5lc192aW9saW5fY29tcGFyZS4yKGRhdGFzZXQgPSBzY2NfbXliX3BhdGllbnRzLCBwcmVmaXggPSAicGF0aWVudCIscHJlX29uID0gYygiSFBWLW5lZ2F0aXZlIiwiSFBWLXBvc2l0aXZlIiksdGVzdCA9ICJ3aWxjb3gudGVzdCIscHJvZ3JhbXMgPSB0b3BfZ2VuZXMsIHJldHVybl9saXN0ID0gRixjb21iaW5lX3BhdGllbnRzID0gVCkgK3NjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsMS41KSkgKyBsYWJzKGZpbGwgPSAiIikreWxhYigiTG9nVFBNIikreGxhYigiR2VuZSIpK3RoZW1lKGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQpKSsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiNGODc2NkQiLCAiY3lhbjMiKSkKcApgYGAKCgpgYGB7cn0KcGRmKGZpbGUgPSAiLi9GaWd1cmVzL1NDQ19IUFZfVG9wX3Zpb2xpbi5wZGYiLHdpZHRoID0gMTAsaGVpZ2h0ID0gNSkKcApkZXYub2ZmKCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD0xM30KbXlwbG90cyA8LSBsaXN0KCkgICMgbmV3IGVtcHR5IGxpc3QKCmZvciAocGF0aWVudF9uYW1lIGluIGMoIlNDQzIiLCAiU0NDMyIsICJTQ0M0IiwgIlNDQzUiKSkgewogIHBhdGllbnRfZGF0YSA9IHN1YnNldCh4ID0gc2NjX215Yl9wYXRpZW50cywgc3Vic2V0ID0gb3JpZy5pZGVudCA9PSBwYXRpZW50X25hbWUpCiAgZGYgID0gRmV0Y2hEYXRhKG9iamVjdCA9IHBhdGllbnRfZGF0YSwKICAgICAgICAgICAgICAgICAgdmFycyA9IGMoImhwdl9wb3NpdGl2ZSIsICJNWUJfcG9zaXRpdmUiKSkgJT4lIGRyb3BsZXZlbHMoKQogIHRlc3QgPSBmaXNoZXJfdGVzdCh0YWJsZShkZikpCiAgcCA9IGdnYmFyc3RhdHMoCiAgICBkZiwKICAgIE1ZQl9wb3NpdGl2ZSwKICAgIGhwdl9wb3NpdGl2ZSwKICAgIHJlc3VsdHMuc3VidGl0bGUgPSBGQUxTRSwKICAgIHN1YnRpdGxlID0gcGFzdGUwKCJGaXNoZXIncyBleGFjdCB0ZXN0IiwgIiwgcC12YWx1ZSA9ICIsCiAgICAgICAgICAgICAgICAgICAgICB0ZXN0JHApCiAgLHRpdGxlID0gcGF0aWVudF9uYW1lKQogIG15cGxvdHNbW3BhdGllbnRfbmFtZV1dIDwtIHAgICMgYWRkIGVhY2ggcGxvdCBpbnRvIHBsb3QgbGlzdAoKfQpnZ2FycmFuZ2UocGxvdGxpc3QgPSBteXBsb3RzLG5jb2wgPSA0LG5yb3cgPSAxKQoKYGBgCmBgYHtyfQogIGZpc2hlci50ZXN0KHRhYmxlKGRmKSkKICBmaXNoZXJfdGVzdCh0YWJsZShkZikpCgpgYGAKCjxzY3JpcHQgc3JjPSJodHRwczovL2h5cG90aGVzLmlzL2VtYmVkLmpzIiBhc3luYz48L3NjcmlwdD4KCg==